package top.hepingan.java.service.Impl.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import top.hepingan.java.common.Result;
import top.hepingan.java.entity.RedPacket;
import top.hepingan.java.entity.RedPacketReceive;
import top.hepingan.java.mapper.IRedPacketService;
import top.hepingan.java.mapper.RedPacketMapper;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import top.hepingan.java.mapper.RedPacketReceiveMapper;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantLock;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author author
 * @since 2025-11-08
 */
@Service
public class RedPacketServiceImpl extends ServiceImpl<RedPacketMapper, RedPacket> implements IRedPacketService {
    @Autowired
    private RedPacketReceiveMapper redPacketReceiveMapper;

    // 用于存储每个红包的锁
    private final ConcurrentHashMap<Long, ReentrantLock> lockMap = new ConcurrentHashMap<>();
    @Override
    @Transactional
    public Result getRedPacket(RedPacket redPacket, Long userId) {
        Long redPacketId = redPacket.getId();
        // 获取红包对应的锁，如果没有就创建
        ReentrantLock lock = lockMap.computeIfAbsent(redPacketId, id -> new ReentrantLock());
        lock.lock();
        try {
            // 查询红包最新数据，带行锁防止超领
            RedPacket dbPacket = baseMapper.selectById(redPacketId);
            // 调用校验工具类
            String errorMsg = validate(dbPacket);
            if (errorMsg != null) {
                if (dbPacket != null && (dbPacket.getRemainCount() <= 0 || dbPacket.getRemainAmount().compareTo(BigDecimal.ZERO) <= 0)) {
                    dbPacket.setStatus(1);
                    baseMapper.updateById(dbPacket);
                }
                return Result.error(errorMsg);
            }
            // 计算领取金额
            BigDecimal amount = computeAmount(dbPacket);
            // 更新红包剩余金额和数量
            dbPacket.setRemainAmount(dbPacket.getRemainAmount().subtract(amount));
            dbPacket.setRemainCount(dbPacket.getRemainCount() - 1);
            if (dbPacket.getRemainCount() == 0 || dbPacket.getRemainAmount().compareTo(BigDecimal.ZERO) <= 0) {
                dbPacket.setStatus(1);
            }
            baseMapper.updateById(dbPacket);

            // 插入领取记录
            RedPacketReceive rec = new RedPacketReceive();
            rec.setRedPacketId(redPacketId);
            rec.setUserId(userId);
            rec.setAmount(amount);
            rec.setReceiveTime(LocalDateTime.now());
            redPacketReceiveMapper.insert(rec);

            return Result.ok().setData(amount);


        }catch (Exception e)
        {

        }finally {
            lock.unlock();
            RedPacket dbPacket = baseMapper.selectById(redPacketId);
            if (dbPacket != null && dbPacket.getStatus() != 0) {
                // 只有当锁还绑定当前对象时才删除
                lockMap.remove(redPacketId, lock);
            }
        }
        return null;
    }

    /**
     * 红包金额计算
     */
    private BigDecimal computeAmount(RedPacket packet) {
        if (packet.getType() == 0 || packet.getRemainCount() == 1) {
            // 普通红包或最后一个红包：平均分
            return packet.getRemainAmount()
                    .divide(BigDecimal.valueOf(packet.getRemainCount()), 2, RoundingMode.DOWN);
        }

        // 拼手气红包
        BigDecimal avg = packet.getRemainAmount()
                .divide(BigDecimal.valueOf(packet.getRemainCount()), 2, RoundingMode.DOWN);
        BigDecimal min = avg.multiply(packet.getMinRatio());
        BigDecimal max = avg.multiply(packet.getMaxRatio());

        double random = min.doubleValue() + Math.random() * (max.doubleValue() - min.doubleValue());
        BigDecimal amt = BigDecimal.valueOf(random).setScale(2, RoundingMode.DOWN);

        // 防止领取金额超过剩余金额
        if (amt.compareTo(packet.getRemainAmount()) > 0) amt = packet.getRemainAmount();
        return amt;
    }

    /**
     * 校验红包是否可领取
     * @param redPacket 红包对象
     * @return 错误信息，如果为空表示可领取
     */
    public String validate(RedPacket redPacket) {
        if (redPacket == null) return "红包不存在";
        if (redPacket.getStatus() != 0) return "红包已结束";
        if (redPacket.getRemainCount() <= 0 || redPacket.getRemainAmount().compareTo(BigDecimal.ZERO) <= 0) {
            return "红包已被领完";
        }
        return null;
    }

}
